use super::time::{SysTime,Clocker,UClock,UClockData,UTime,SysConvertor,CpuClock};
use super::ls::{werror};
use super::pair::pair;
use super::clk::{ClockTracer,ClockTrace};

use std::thread;
use std::time::Duration;

const PhaseSize: usize = 60usize;

#[derive(Debug)]
pub struct Phase {
    e : [pair<UTime,SysTime>;PhaseSize],
    convertor : UClockData,
    p : usize,
    pub r : (f64,f64),
}

impl Phase {
    pub fn new(data : &UClockData) -> Self {
        Self {
            e : [pair::<UTime,SysTime>::default();PhaseSize],
            convertor : *data,
            p: 0usize,
            r:(0f64,0f64),
        }
    }
    pub fn set_zero(&mut self) { 
        self.convertor.self_start = self.convertor.from_sys(&self.e[PhaseSize-1].1);
        self.convertor.cpu_start= SysTime(self.e[PhaseSize-1].1.0 + self.r.0 as i64);
        self.p = 0usize; 
    }
    pub fn finalize(&mut self) {
        self.r=werror(&self.e,&self.convertor);
    }
}

impl ClockTracer for Phase {
    fn update(&mut self,p :pair::<UTime,SysTime>) -> bool {
        self.e[self.p]= p;
        self.p += 1;
        self.p %= PhaseSize;
        true
    }
    fn getdata(&self) -> UClockData {
        self.convertor.clone()
    }
    
    fn error(&self) -> Option<f64> { 
        Some(self.r.1) 
    }
}

#[derive(Debug)]
pub struct LSandPhase<T:ClockTracer+Default> {
    pub l0 : T,
    pub l1 : Phase,
}

impl<T:ClockTracer+Default> Default for LSandPhase<T> {
    fn default() -> Self {
        let l0 = T::default();
        let l1 = Phase::new(&l0.getdata());
        Self { l0, l1 }
    }
}

impl<T:ClockTracer+Default> LSandPhase<T> {
    pub fn one_ls<C:Clocker+Default>(&mut self) -> Option<UClock<C>> {
        let mut tempc = C::default();
        let p = pair(tempc.now(),SysTime::now());
        if self.l0.update(p) {
            let d = self.l0.getdata();
            self.l1.convertor.rate_nano = d.rate_nano;
            for _ in 0..PhaseSize {
                let p = pair(tempc.now(),SysTime::now());
                self.l1.update(p);
                let p = pair(tempc.now(),SysTime::now());
                thread::sleep(Duration::from_millis(100));
            }
            self.l1.finalize();
            println!("{:?} ",self.l1.r);
            self.l1.set_zero();        
            Some(UClock{ data: self.l1.getdata(), clock:C::default()})    
        } else {
            thread::sleep(Duration::from_millis((PhaseSize as u64)*100));
            None
        }
    }
}

pub type Phasex = LSandPhase<ClockTrace<CpuClock>>;